﻿// ## 2023/05/21 # 铃 # 使用262函数重写
// ## 2023/03/29 # 铃 # 创建,目的是为了让AI在粮草不足或者兵力不足时提前撤退

namespace AI部队提前撤退
{
    //=======================================================================================

    class Main
    {
        // 用于存储262
        pk::func262_t @prev_callback_262;
        bool action = false;
        int loc_id;

        Main()
        {
            // 262函数前处理器存储、函数初始化、函数重新定义
            @prev_callback_262 = cast<pk::func262_t @>(pk::get_func(262));
            pk::reset_func(262);
            pk::set_func(262, pk::func262_t(func262));
        }
        //---------------------------------------------------------------------------

        bool func262(pk::unit @unit)
        {
            // 部队所属主城还在的时候执行
            pk::building @building = pk::get_building(pk::get_service(unit));
            if (pk::is_alive(building))
            {
                pk::force @force = pk::get_force(unit.get_force_id());
                AI_withdraw(unit, force, /*is_deployed*/ true);

                if (action)
                    return true;
            }

            if (prev_callback_262 is null)
                return false;
            return prev_callback_262(unit);
        }

        //---------------------------------------------------------------------------

        // 重新设置部队目标的函数
        void AI_withdraw(pk::unit @unit, pk::force @force, bool is_deployed)
        {
            if (!pk::is_alive(unit))
                return;

            if (unit.troops == 0)
                return;

            if (unit.action_done)
                return;
            // 异常状态的部队本回合不设定跳过
            if (unit.status != 部队状态_通常)
                return;

            // 运输部队跳过? 要不要给运输部队生效呢?
            if (unit.type == 部队类型_运输)
                return;

            // 撤退部队无效,避免多次设置
            if (unit.order == 部队任务_撤退)
                return;

            // 排除无法确认所属据点的部队
            if (!pk::is_alive(pk::get_building(pk::get_service(unit))))
                return;

            // 排除玩家部队
            if (pk::is_player_controlled(unit))
                return;

            //健康的部队提前t跳出,减少后面的计算.
            if (unit.troops > 1500 and unit.energy > 20 and int(unit.food * 10 / unit.troops) > 10)
                return;

            main.loc_id = pk::get_building_id(unit.pos);

            pk::person @leader = pk::get_person(unit.leader);
            pk::building @dst = find_withdraw_base(unit);

            int move_days = pk::max(unit_distance[dst.get_id()][pk::get_building_id(unit.pos)], 5); //撤退需要几天
            int food_days = int(unit.food * 10 / unit.troops);      //粮草还够几天
            string target_name = pk::decode(pk::get_name(dst));


           // 兵力小于1000,撤退距离在大约6回合以内撤退,太远就放弃.
            if (unit.troops < 1500)
            {
                pk::set_order(unit, 部队任务_撤退, dst.pos);
                if (pk::is_in_screen(unit.pos))
                    pk::say(pk::encode(pk::format("无力再战,向\x1b[2x{}\x1b[0x撤退吧!", target_name)), leader);
            }

            else if (unit.energy <= 20 and unit.troops < 5000)
            {
                pk::set_order(unit, 部队任务_撤退, dst.pos);
                if (pk::is_in_screen(unit.pos))
                    pk::say(pk::encode(pk::format("士兵们士气低落已无法再战,向\x1b[2x{}\x1b[0x撤退吧!", target_name)), leader);
            }

            else if (food_days <= move_days and food_days <= 10) //如果撤退需要6天,那么第五天就要考虑回家
            {
                pk::set_order(unit, 部队任务_撤退, dst.pos);
                if (pk::is_in_screen(unit.pos))
                    pk::say(pk::encode(pk::format("粮草已尽,已无法再战,向\x1b[2x{}\x1b[0x撤退吧!", target_name)), leader);
            }
        }


        // 寻找撤退据点
        pk::building @find_withdraw_base(pk::unit @unit)
        {
            array<pk::building @> dst_base_arr;
            for (int i = 0; i < 据点_末; i++)
            {
                pk::building @dst_base = pk::get_building(i);

                if (!pk::is_alive(dst_base))
                    continue;

                //太远不行
                if (unit_distance[main.loc_id][i] > 10)
                    continue;

                    //判断势力
                if (dst_base.get_force_id() != unit.get_force_id())
                    continue;

                dst_base_arr.insertLast(dst_base);
            }

            dst_base_arr.sort(function(a, b) {
                return unit_distance[main.loc_id][a.get_id()] < unit_distance[main.loc_id][b.get_id()];
            });

            if (dst_base_arr.length <= 0)
                return pk::get_building(pk::get_service(unit));
            else return  dst_base_arr[0];
        }

    } Main main;
}
